\documentclass[UTF8]{ctexart}
\usepackage{xltxtra}
\usepackage{graphicx}
\usepackage{float}
\usepackage{subfigure}
%图片排版

\usepackage{listings,xcolor}

\usepackage[top=2cm, bottom=2cm, left=2cm, right=2cm]{geometry}  
%\usepackage{algorithm}  
%\usepackage{algorithmicx}  
%\usepackage{algpseudocode}  
\usepackage{amsmath}

\title{五则运算计算器的实现}
\author{陈乐瑶\\ 信息与计算科学\quad 3210103710}
\date{\today}
\begin{document}
\maketitle
\pagestyle{plain}
\lstset{numbers=left,
numberstyle=\tiny,
keywordstyle=\color{blue!70}, commentstyle=\color{red!50!green!50!blue!50},
frame=shadowbox,
rulesepcolor=\color{red!20!green!20!blue!20},
columns=flexible
}

\section{设计思路}
\begin{itemize}
\item 通过栈和队列实现中缀表达式到后缀表达式的转换
\item 通过栈实现后缀表达式的计算
\end{itemize}

\subsection{类设计}
在$calculator.h$中给出了类的设计，其中属性主要包括一个用于存放运算符的栈$op$、一个用于存放后缀表达式的队列$exp$和运算结果$result$。由于运算对象为浮点数，所以队列的数据类型采用字符串。而函数主要包括构造函数、后缀表达式转换函数、计算函数以及错误输入处理函数。
\begin{lstlisting}[language={[ANSI]C++}]
class calculator
{
 private:
  std::stack<char> op;//存放运算符
  std::queue<std::string> exp;//存放后缀表达式
  double result;//运算结果

 public:
  calculator();//构造函数
  void calculate();//计算整体过程
  void get_postfix();//中缀表达式转换为后缀表达式
  void calresult();//计算后缀表达式
  double get_result();//获得运算结果
  void _err_exp(int i);//处理错误的输入信息，i用于区分类别
};
\end{lstlisting}

\subsection{函数实现设计}
\subsubsection{后缀表达式转换函数}
\begin{itemize}
\item \textbf{输入：}由于求解的表达式任意长度，故选择使用$getchar()$逐个输入字符并处理。
\item \textbf{数字：}由于逐个输入字符不确定数字输入是否结束，故设计布尔型的$digit$进行判定。而布尔型的$point$则对小数判定，检查输入的小数点是否符合逻辑。
\item \textbf{负数：}由于负数只出现在表达式最前或左括号右边，所以在这两种情况时处理为0和减法的组合即可。
\item \textbf{括号：}出现左括号时直接入栈；出现右括号时将栈内最上方的左括号上的运算符全部入队并出栈后弹出该左括号，实现括号匹配以及括号内的运算优先进行。
\item \textbf{运算符：}若栈内有同级或更高级的运算符时先将其入队并出栈，实现运算的优先级次序，后再将该运算符入栈；若无同级或更高级的运算符时，直接入栈。需要注意的是，乘方运算次序为从右到左，相当与无同级或更高级，且0的非正指数幂无意义。
\item \textbf{错误检查：}根据括号、数字、小数点、运算符的出现逻辑设计了布尔型的$opright$进行检查。
\end{itemize}

\subsubsection{计算函数}
\begin{itemize}
\item 由于队列$exp$的数据类型为字符串，故只对字符串第一位进行判定。其中string到double的转换用了<cstdlib.h>库下的atof()函数以及<string>的c\_str()函数。
\item 设定$num1$和$num2$为两个运算对象，始终保持其为栈$cal$最上方的两个数据，用于计算。
\item 依次读取$exp$的字符串。若为数字则入栈并出队，若为运算符则对栈内最上方的两个数据进行运算，并弹出这两个元素替换为运算结果入栈。
\end{itemize}

\subsubsection{错误检测函数}
设置简单的int变量i来区分错误类型，函数主体结构如下：
\begin{lstlisting}[language={[ANSI]C++}]
void calculator::_err_exp(int i)
{
  if(i==0)
    std::cerr<<"错误：除数为0"<<std::endl;
  else if(i==1)
    ...
  std::exit(-1);
}
\end{lstlisting}

\section{测试说明}
\subsection{正常运算测试}
以参考算例中input1和input2两个正数运算以及对应改动的两个负数运算为例：
\begin{figure}[H]
  \centering
  \includegraphics[width=0.45\textwidth]{fig1.png}
  \includegraphics[width=0.45\textwidth]{fig2.png}
  \includegraphics[width=0.45\textwidth]{fig12.png}
  \includegraphics[width=0.45\textwidth]{fig21.png}
  \caption{正常运算测试}
\end{figure}

经测试，计算器可以正常进行运算，且运算结果正确。

\subsection{错误输入测试}
我们在input1的基础上进行一些不同类型的错误修改：

\subsubsection{括号不匹配}
\begin{figure}[H]
  \centering
  \includegraphics[width=0.45\textwidth]{fig31.png}
  \includegraphics[width=0.45\textwidth]{fig32.png}
  \caption{括号不匹配}
\end{figure}

\subsubsection{运算符不合逻辑}
\begin{figure}[H]
  \centering
  \includegraphics[width=0.45\textwidth]{fig41.png}
  \includegraphics[width=0.45\textwidth]{fig42.png}
  \caption{运算符不合逻辑}
\end{figure}

\subsubsection{除数为0}
\begin{figure}[H]
  \centering
  \includegraphics[width=0.45\textwidth]{fig51.png}
  \includegraphics[width=0.45\textwidth]{fig52.png}
  \caption{除数为0}
\end{figure}

\subsubsection{乘方输入}
\begin{figure}[H]
  \centering
  \includegraphics[width=0.45\textwidth]{fig81.png}
  \includegraphics[width=0.45\textwidth]{fig82.png}
  \includegraphics[width=0.45\textwidth]{fig83.png}
  \includegraphics[width=0.45\textwidth]{fig84.png}
  \caption{上为乘方次序的正确验证，下为乘方无意义的错误验证}
\end{figure}

\subsubsection{小数输入不合逻辑}
\begin{figure}[H]
  \centering
  \includegraphics[width=0.3\textwidth]{fig61.png}
  \includegraphics[width=0.3\textwidth]{fig62.png}
  \includegraphics[width=0.3\textwidth]{fig63.png}
  \caption{小数输入不合逻辑}
\end{figure}

\subsubsection{运算符超范围}
\begin{figure}[H]
  \centering
  \includegraphics[width=0.45\textwidth]{fig71.png}
  \includegraphics[width=0.45\textwidth]{fig72.png}
  \caption{运算符超范围}
\end{figure}

经测试，计算器能够检测大部分错误输入并给出错误信息。


\subsection{内存泄漏测试}
\begin{figure}[H]
  \centering
  \includegraphics[width=0.6\textwidth]{fig0.png}
  \caption{内存泄漏测试}
\end{figure}

经测试，计算器无内存泄漏，程序安全。

\end{document}
